package goplatform

import (
	"errors"
	"reflect"
)

type FieldI interface {
	GetName() string
	CodeOrmStates() []string
	EventUpdate() string

	// GetErrors() []error -> Read f.Errs
	//beforeSave(model *Model) error
	//afterSave(model *Model) error
}

type FieldConfig struct {
	RegisteredFields map[string]FieldI
	OrmTagName       string
}

const (
	DefaultFieldOrmTagName = "orm"
)

var (
	fieldFactory FieldConfig
	//FieldOrmTagName = "orm"
)

func init() {
	//
	//if len(RegisterFields) < 1 {
	//	RegisterFields = make(map[string]FieldI)
	//}
	fieldFactory = FieldConfig{
		RegisteredFields: make(map[string]FieldI),
		OrmTagName:       DefaultFieldOrmTagName,
	}
	//fmt.Println("fieldFactory", fieldFactory)
}

func GetFieldFactory() (*FieldConfig, error) {
	return &fieldFactory, nil
}

//https://gist.github.com/hvoecking/10772475

func (f *FieldConfig) RegisterFieldType(fb FieldI) error {
	fbInstance := reflect.TypeOf(fb).Elem()
	fbValue := reflect.ValueOf(fb).Elem()

	fbNameField := fbValue.FieldByName("Name")
	if fbNameField.IsValid() && fbNameField.String() == "" {
		return errors.New("Register FieldType no 'Name' Field Or 'Name' is Empty. ")
	}
	if _, hasIt := fbInstance.FieldByName("Errs"); !hasIt {
		return errors.New("Register FieldType no 'Errs' Field. ")
	}

	//fbFieldElements, _ := fbInstance.FieldByName("Elements")
	//log.Printf("\n!!!!! RegisterFieldType fbFieldElements %+v\n", fbFieldElements)

	//userOrmState := fb.CodeOrmStates()
	//if len(userOrmState) == 0 {
	//	tElementsType := fbFieldElements.Type
	//	log.Printf("\n!!!!! RegisterFieldType fbFieldElements %+v\n", f._elementOrmState(tElementsType))
	//}

	//for i := 0; i < fbInstance.NumField(); i++ {
	//	log.Println("f1.String() => index:", i, " FieldName:", fbInstance.Field(i).Name)
	//}

	name := fb.GetName()
	f.RegisteredFields[name] = fb
	return nil
}

func (f *FieldConfig) _elementOrmState(elementsType reflect.Type) []string {
	tElementsNum := elementsType.NumField()
	var ormElementMap []string
	for i := 0; i < tElementsNum; i++ {
		ormTag := elementsType.Field(i).Tag.Get(f.OrmTagName)
		if ormTag != "" {
			ormElementMap = append(ormElementMap, ormTag)
		}
	}
	return ormElementMap
}

func (f *FieldConfig) GetFieldType(name string) (FieldI, error) {
	fb, found := f.RegisteredFields[name]
	//var _ Shape = (*Square)(nil)
	if found {
		return fb, nil
	}
	return &FieldUnDefined{}, errors.New("Not Found (" + name + ") Field Type is Registered.")
}

//func (f *FieldConfig) GenOrmDefined() string {
//
//	return ""
//}
